var OverlayControl = {
  controlId: 'tails_overlayControl',
  deckId: 'tails_overlayDeck',
  initialized: false,

  /* Show this control */
  show: function() {
    this._initialize();

    this.showObjectList();
    this.objectList.objects = [];
    this.objectList.scriptErrors = [];

    var control = this._getControl();
    if (!control.hidden) return;
    control.style.zIndex = 1000;
    control.style.display = 'block';
    control.style.bottom = $$("status-bar").boxObject.height + "px";
    control.style.right = "20px";
    control.style.width = "640px";
    control.style.height = "480px";
    control.style.left = "";
    control.hidden = false;
  },
  
  showObjectList: function() {
    this._getDeck().selectedIndex = 0;
  },
  showObjectDetails: function(objIndex) {
    if (objIndex < 0 || objIndex >= this.objectList.objects.length)
      alert("invalid object: " + objIndex + ", length=" + this.objectList.objects.length);
      
    this.objectDetails.showObject(this.objectList.objects[objIndex]);
    this._getDeck().selectedIndex = 1;
  },

  hide: function() {
    var control = this._getControl();
    if (control.hidden) return;

    control.style.zIndex = 20;
    control.style.display = 'none';
    control.style.bottom = "0px";
    control.style.right = "0px";
    control.style.width = "1px";
    control.style.height = "1px";
    control.style.left = "";
    control.hidden = true;
  },

  isVisible: function() {
    return !this._getControl().hidden;
  },

  // save function for tails scripts.
  saveFile: function(objectIndex, actionIndex){
    var wrapper = this.objectList.objects[objectIndex];
    var action  = wrapper.actions[actionIndex];
    
    var data = action.getData();
    var fileName = data.fileName.replace(/[^A-z0-9\.]+/g, '_');
    var contents = data.contents;
    
    //create a new temporary file
    var file = Components.classes["@mozilla.org/file/directory_service;1"]
        .getService(Components.interfaces.nsIProperties)
        .get("TmpD", Components.interfaces.nsIFile);
    file.append(fileName);

    if (!file.exists()) {
      file.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0664);
    }

    var ios = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
    var fileHandler = ios.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
    var url = fileHandler.getURLSpecFromFile(file);


    var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
        .createInstance(Components.interfaces.nsIFileOutputStream);

    // use 0x02 | 0x10 to open file for appending.
    foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
    foStream.write(contents, contents.length);
    foStream.close();

    //window.top.getBrowser().selectedBrowser.loadURI(url);
    window.top.getBrowser().selectedBrowser.loadURI(url);
  },
  
  // AJAX call for tails scripts
  callAJAX: function(objectIndex, actionIndex) {
    var wrapper = this.objectList.objects[objectIndex];
    var action  = wrapper.actions[actionIndex];
    var ajax    = action.getAJAX();
    
    var xhr = new XMLHttpRequest();
    xhr.open("GET", ajax.url, true, null, null);
    
    var headers = {
      'X-Requested-With': 'XMLHttpRequest',
      'Accept':           'text/javascript, text/html, application/xml, text/xml, */*'
    };

    for (var name in headers)
      xhr.setRequestHeader(name, headers[name]);
      
    xhr.onreadystatechange = function() {
      var readyState = xhr.readyState;
      if (readyState == 4)
        ajax.callback(xhr);
    }
    
    xhr.send(null);
  },

  /*
   * INTERNAL FUNCTIONS
   */
  _getControl: function() {
    return $$(this.controlId);
  },
  _getDeck: function() {
    return $$(this.deckId);
  },

  _initialize: function() {
    if (this.initialized) return;
    this.initialized = true;
    this.objectList.initialize();
    this.objectDetails.initialize();
  },
 
  /* Currently not used, but might be useful later */ 
  _setStyle: function(node, hash) {
    var style = "";
    for (var m in hash) {
      style += m.replace(/([A-Z])/g, "-$1").toLowerCase() + ": " + hash[m] + ";";
    }
    node.setAttribute('style', style);
  },
  
  end: null
};

/*
 * Frame Control Base Class
 */
TailsNS.IframeControl = function(iframeId) { this.iframeId = iframeId; };
TailsNS.IframeControl.prototype = {
  loaded: false,

  initialize: function() {
    this._getIframe().addEventListener("load",
      TailsNS.listener(this, '_setLoaded'), true);
  },

  _setLoaded: function(e) {
    var iframe = this._getIframe();
    iframe.contentWindow.overlayControl = OverlayControl;
    this.loaded = true;
    if (this._onLoaded) this._onLoaded(iframe);
  },
  
  $: function(id) {
    return this._getIframe().contentDocument.getElementById(id);
  },
  _getIframe: function() {
    return $$(this.iframeId);
  }
};

/*
 * A wrapper object to contain the object and its functions.
 */
OverlayControl.ObjectWrapper = function(object, index) {
  this.object = object;
  this.index  = index;
  return this;
}
OverlayControl.ObjectWrapper.prototype = {
}

/*
 * Object List Control
 */
OverlayControl.objectList = TailsNS.extendObject(new TailsNS.IframeControl('tails_objectListIframe'), {
  preLoadObjects: [],
  objects: [],
  scriptErrors: [],
 
  tabSelected: function() {
    var tabs = $$('tails_overlayTabs');
    tabs.selectedItem.id.match(/tab_(.*)/);
    var name = RegExp.$1;
    this._showObjects(name);
  },

  addObject: function(object) {
    var wrapper = new OverlayControl.ObjectWrapper(object, this.objects.length);
    this.objects.push(wrapper);

    if (!this.loaded) {
      this.preLoadObjects.push(wrapper);
    } else {
      this._addObject(wrapper);
    }
  },

  /*
   * INTERNAL FUNCTIONS
   */
  _onLoaded: function(iframe) {
    this._resetTabs();

    var doc = iframe.contentDocument;
    doc.body.innerHTML = TailsNS.getMessage("overlay_html_body");

    for (var i=0; i<this.preLoadObjects.length; i++) {
      this._addObject(this.preLoadObjects[i]);
    }
    this.preLoadObjects = [];
  },
   
  _resetTabs: function() {
    var tabs = $$('tails_overlayTabs');
    var tabsToRemove = [];
    // doing the remove afterwards first loop so iterating isn't altered.
    for (var i=0; i<tabs.childNodes.length; i++) {
      var e = tabs.childNodes[i];
      if (e.tagName.toLowerCase() == 'tab' && e.id != "tab_all") {
        tabsToRemove.push(e);
      }
    }
    for (var i=0; i<tabsToRemove.length; i++) {
      tabsToRemove[i].parentNode.removeChild(tabsToRemove[i]);
    }
    tabs.__count = 0;
    tabs.selectedIndex = 0;
  },

  _showTab: function(nm) {
    var tabs = $$('tails_overlayTabs');
    var tab = tabs.ownerDocument.getElementById("tab_"+nm);
    if (!tab) {
      tab = tabs.ownerDocument.createElement("tab");
      tab.__count = 0;
      tab.id = "tab_" + nm;
      tabs.appendChild(tab);
    }
    tab.__count++;
    tab.setAttribute("label", TailsNS.getMessage("tab_" + nm, [tab.__count]));

    tabs.__count++;
    var allTab = tabs.ownerDocument.getElementById("tab_all");
    allTab.setAttribute("label", TailsNS.getMessage("tab_all", [tabs.__count]));
  },
  
  _addObject: function(wrapper) {
    var object = wrapper.object;
    var args = [];
    
    if (object.generic.icon)
      args.push(object.generic.icon);
    else
      args.push("chrome://tails/content/images/" + object.__name + ".png");

    args.push((object.generic.label || TailsNS.getMessage("unknown_label")));

    if (object.generic.url)
      args.push(TailsNS.getMessage("overlay_html_url", [object.generic.url]));
    else
      args.push("");

    if (object.generic.description)
      args.push(object.generic.description);
    else
      args.push("");

    args.push(this._getActions(wrapper));

    args.push(wrapper.index);

    var doc = this._getIframe().contentDocument;
    
    var div = doc.createElement("div");
    div.__object_type = object.__name;
    div.setAttribute("class", "object_content");
    div.innerHTML = TailsNS.getMessage("overlay_html_object", args);
    this.$('object_list').appendChild(div);

    this._showTab(object.__name);
    var tab = $$('tab_' + object.__name);
    if (tab && tab.hidden) tab.hidden = false;
  },
  
  _showObjects: function(n) {
    var divs = this._getIframe().contentDocument.getElementsByTagName("div");
    for (var i=0; i<divs.length; i++) {
      if (divs[i].getAttribute("class") == "object_content") {
        if (n == "all" || divs[i].__object_type == n)
          divs[i].style.display = 'block';
        else
          divs[i].style.display = 'none';
      }
    }
  },

  _getActions: function(wrapper) {
    var actions =  TailsNS.ScriptManager.getActions(wrapper.object, this.scriptErrors);
    wrapper.actions = actions;

    var s = "";
    for (var i=0; i<actions.length; i++) {
      try {
        var url = null;
        
        // If the action renders a URL
        if (actions[i].getURL) {
          url = actions[i].getURL();
          
        // If the action renders a data file.
        } else if (actions[i].getData) {
          url = "javascript:window.overlayControl.saveFile(" + wrapper.index + "," + i + ");";
        
        // If the action is an AJAX call.
        } else if (actions[i].getAJAX) {
          var ajax = actions[i].getAJAX();
          if (ajax)
            url = "javascript:window.overlayControl.callAJAX(" + wrapper.index + "," + i + ");";
        }
        
        if (url) {
          if (s != "") s += " | ";
          s += "<a href='" + url  + "'"
          if (!url.match(/^javascript:.*/))
            s+= " target='_blank'";
          s += ">" + actions[i].getLabel() + "</a>";
        }
          
      } catch (err) {
        alert(actions[i].__name + ": " + err);
      }
    }
    return s;
  },
  
  end: null
});


/*
 * Object Details Control
 */
OverlayControl.objectDetails = TailsNS.extendObject(new TailsNS.IframeControl('tails_objectDetailsIframe'), {
  wrapper: null,
  
  showObject: function(wrapper) {
    if (!wrapper) return;
    this.wrapper = wrapper;
    this._getIframe().contentDocument.location.href = 'about:blank';
  },
  
  /*
   * INTERNAL FUNCTIONS
   */
  _onLoaded: function(iframe) {
    if (this.wrapper) {
      if (this._getIframe().contentDocument.location.href != 'about:blank')
        this._showObject();
      else {
        var template = "chrome://tails/content/details/" + this.wrapper.object.__name + ".html";
        this._getIframe().contentDocument.location.href = template;
      }
    }
  },
  
  _showObject: function() {
    TailsNS.HTMLTemplate.apply(this.wrapper.object, this._getIframe().contentDocument);
  },

  end: null
});
